﻿// Inner Kit 库
// 用于打印的通用工具类
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于输出流信息
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-16

#include "klog.h"
#include <Windows.h>
#include <chrono>
#include <graphics/imath.h>
#include <kfile.h>
#include <kstring.h>

using namespace DirectX;
using namespace ifire;

namespace ikit {

static FILE* log_stream = nullptr;
static const char* log_filename = nullptr;

static int space_count = 0;

// 最大能够允许的记录行数，防止某些特殊情况导致LOG暴涨
static size_t max_log_line = 2048;
// 当前的记录
static size_t current_log_line = 0;

static bool is_log_full() { return (current_log_line++ > max_log_line); }

void set_max_log_line(size_t max_count) { max_log_line = max_count; }

void print_binary_64(uint64_t mask) {
  for (int i = 63; i >= 0; i--) {
    printf("%d", (int)(mask >> i) & 1);
    if (i % 8 == 0 && i != 0) printf(" "); // 每8位加空格分隔
  }
  printf("\n");
}

void print_binary_32(uint32_t mask) {
  for (int i = 31; i >= 0; i--) {
    printf("%d", (mask >> i) & 1);
    if (i % 8 == 0 && i != 0) printf(" "); // 每8位加空格分隔
  }
  printf("\n");
}

void print_tab(const char* text) {
  for (int i = 0; i < space_count; i++) {
    KPRINT(" ");
  }
  if (text != nullptr) {
    KPRINT(text);
  }
}

void add_tab(int value) { space_count += value; }

void back_tab(int value) {
  space_count -= value;
  if (space_count < 0) {
    space_count = 0;
  }
}

void reset_tab() { space_count = 0; }

void print_mat(DirectX::FXMMATRIX mat, bool use_tab) {
  XMFLOAT4X4 dest;
  XMStoreFloat4x4(&dest, mat);
  print_mat(dest, use_tab);
}

void print_mat(DirectX::XMFLOAT4X4 mat, bool use_tab) {
  print_vec4(mat._11, mat._12, mat._13, mat._14, use_tab);
  print_vec4(mat._21, mat._22, mat._23, mat._24, use_tab);
  print_vec4(mat._31, mat._32, mat._33, mat._34, use_tab);
  print_vec4(mat._41, mat._42, mat._43, mat._44, use_tab);
}

void print_mat_break(DirectX::FXMMATRIX mat, bool use_tab) {
  if (use_tab) {
    print_tab();
  }
  auto pos = imath::TranslationFromMatrix(mat);
  auto rot = imath::RotationFromMatrix(mat);
  imath::Scale(rot, DEG_TO_RAD);
  auto scl = imath::ScalingFromMatrix(mat);
  print("P[%0.3f %0.3f %0.3f] R[%0.0f %0.0f %0.0f] S[%.3g %.3g %.3g]\n", pos.x,
      pos.y, pos.z, rot.x, rot.y, rot.z, scl.x, scl.y, scl.z);
}

void print_mat_break(DirectX::XMFLOAT4X4 mat, bool use_tab) {
  print_mat_break(XMLoadFloat4x4(&mat), use_tab);
}

void print_vec3(DirectX::FXMVECTOR vec, bool use_tab) {
  XMFLOAT3 dest;
  XMStoreFloat3(&dest, vec);
  print_vec3(dest, use_tab);
}

void print_vec3(DirectX::XMFLOAT3 vec, bool use_tab) {
  print_vec3(vec.x, vec.y, vec.z);
}

void print_vec3(float x, float y, float z, bool use_tab) {
  if (use_tab) {
    print_tab();
  }
  KLOG("%f %f %f", x, y, z);
}

void print_vec4(DirectX::FXMVECTOR vec, bool use_tab) {
  XMFLOAT4 dest;
  XMStoreFloat4(&dest, vec);
  print_vec4(dest, use_tab);
}

void print_vec4(DirectX::XMFLOAT4 vec, bool use_tab) {
  print_vec4(vec.x, vec.y, vec.z, vec.w, use_tab);
}

void print_vec4(float x, float y, float z, float w, bool use_tab) {
  if (use_tab) {
    print_tab();
  }
  KLOG("%f %f %f %f", x, y, z, w);
}

void print_eular(DirectX::FXMVECTOR vec, bool use_tab) {
  auto euler = imath::QuaternionToEuler(vec);
  imath::Scale(euler, DEG_TO_RAD);
  print_vec3(euler, use_tab);
}

void error(const char* format, ...) {
  if (is_log_full()) {
    return;
  }

  // 先不管怎么样，先输出到Windows的平台
  char buffer[2048];

  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  vsprintf_s(buffer, format, ap);
  va_end(ap);

  OutputDebugStringA(buffer);
  OutputDebugStringA("\n");

  printf("\n");
}

void interval_log(const char* format, ...) {
  if (is_log_full() || check_log_interal() == false) {
    return;
  }

  // 先不管怎么样，先输出到Windows的平台
  char buffer[1024];

  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  vsprintf_s(buffer, format, ap);
  va_end(ap);

  OutputDebugStringA(buffer);
  OutputDebugStringA("\n");

  printf("\n");
}

bool check_log_interal() {
  static auto lastExecutionTime =
      std::chrono::time_point<std::chrono::steady_clock>();
  auto currentTime = std::chrono::steady_clock::now();

  bool is_frist =
      lastExecutionTime == std::chrono::time_point<std::chrono::steady_clock>();

  // 计算距离上次执行的时间差
  auto duration = std::chrono::duration_cast<std::chrono::seconds>(
      currentTime - lastExecutionTime);

  if (is_frist == false && duration.count() < 1) {
    return false;
  }

  // 更新上次执行的时间
  lastExecutionTime = currentTime;
  return true;
}

void log(const char* format, ...) {
  if (is_log_full()) {
    return;
  }

  // 先不管怎么样，先输出到Windows的平台
  char buffer[1024];

  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  vsprintf_s(buffer, format, ap);
  va_end(ap);

  OutputDebugStringA(buffer);
  OutputDebugStringA("\n");

  printf("\n");
}

void print(const char* format, ...) {
  if (is_log_full()) {
    return;
  }

  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  va_end(ap);
}

void printv(const char* format, va_list ap) {
  if (is_log_full()) {
    return;
  }
  vprintf(format, ap);
}

void print_text(const char* text) {
  if (is_log_full()) {
    return;
  }

  OutputDebugStringA(text);
  OutputDebugStringA("\n");
  printf(text);
}

std::string get_log() {
  if (log_stream == nullptr) {
    return std::string();
  }

  // 关闭输出流
  fclose(log_stream);
  // 得到文字
  auto text = ikit::read_txt_file(log_filename);
  // 重新打开输出流
  set_log_output_file(log_filename, true);

  // 将行尾进行转化
  return replace_with_CrLf(text);
}

void set_log_output_file(const char* filename, bool is_append) {
  log_filename = filename;
  freopen_s(&log_stream, filename, is_append ? "a" : "w", stdout);
}

} // namespace ikit